package com.opengate.base.intercept;

import com.opengate.base.constants.AppConstants;
import com.opengate.base.utils.IpAddressUtil;
import com.opengate.base.utils.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author 曳戈泰尔
 * @version 1.0
 * @description 日志拦截器
 * @date 2023/4/26 5:46 PM
 */
@Slf4j
public class LogInterceptor implements HandlerInterceptor {

    /** 在请求处理之前进行调用（Controller方法调用之前） */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {

        // 记录请求开始时间
        request.setAttribute("start_time", System.currentTimeMillis());
        // 获取请求的路径
        String requestPath = request.getServletPath();

        // 设置请求编号
        String mdcHeadName = request.getHeader(AppConstants.HEADER_RID_NAME);
        if (StringUtils.isBlank(mdcHeadName)) {
            if (StringUtils.isBlank(MDC.get(AppConstants.HEADER_RID_NAME))) {
                MDC.put(AppConstants.HEADER_RID_NAME, SnowFlakeUtil.getId().toString());
            }
        } else {
            MDC.put(AppConstants.HEADER_RID_NAME, mdcHeadName);
        }

        // 设置请求版本version
        String version = request.getHeader(AppConstants.APP_VERSION);
        if (!StringUtils.isEmpty(version)) {
            MDC.put(AppConstants.APP_VERSION, version);
        } else {
            MDC.put(AppConstants.APP_VERSION, "");
        }

        // 设置请求token
        String token = request.getHeader(AppConstants.AUTHORIZATION_HEADER);
        if (!StringUtils.isEmpty(token)) {
            MDC.put(AppConstants.AUTHORIZATION_HEADER, token);
        } else {
            MDC.put(AppConstants.AUTHORIZATION_HEADER, "");
        }

        // 获取请求IP
        String ipAddress = IpAddressUtil.getIpAddress(request);
        if (!StringUtils.isEmpty(ipAddress)) {
            MDC.put(AppConstants.IP_ADDRESS, ipAddress);
        } else {
            MDC.put(AppConstants.IP_ADDRESS, "");
        }

        // 获取用户ID
        String userId = request.getHeader(AppConstants.USER_ID);
        if (!StringUtils.isEmpty(userId)) {
            MDC.put(AppConstants.USER_ID, userId);
        } else {
            MDC.put(AppConstants.USER_ID, "");
        }

        // 设置请求路径
        MDC.put(AppConstants.REQUEST_PATH, requestPath);

        return true;
    }

    /** 请求处理之后进行调用，但是在视图被渲染之前（Controller方法调用之后） */
    @Override
    public void postHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object o,
            ModelAndView modelAndView) {

        // 获取请求的路径
        String requestPath = request.getServletPath();
        // 获取请求开始时间
        long startTime = (long) request.getAttribute("start_time");
        // 获取请求结束时间
        long endTime = System.currentTimeMillis();
        // 计算请求耗时
        long costTime = endTime - startTime;

        // 打印请求耗时
        log.info("requestPath={}，总耗时={}ms", requestPath, costTime);

        // 清除MDC
        MDC.remove(AppConstants.HEADER_RID_NAME);
        MDC.remove(AppConstants.REQUEST_PATH);
        MDC.remove(AppConstants.APP_VERSION);
        MDC.remove(AppConstants.AUTHORIZATION_HEADER);
        MDC.remove(AppConstants.IP_ADDRESS);
        MDC.remove(AppConstants.USER_ID);
    }

    /** 在整个请求结束之后被调用，也就是在DispatcherServlet渲染了对应的视图之后执行（主要是用于进行资源清理工作） */
    @Override
    public void afterCompletion(
            HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse,
            Object o,
            Exception e) {

        // 清楚MDC，检查是否有遗漏，只清除不为空的
        if (StringUtils.isNotBlank(MDC.get(AppConstants.HEADER_RID_NAME))) {
            MDC.remove(AppConstants.HEADER_RID_NAME);
        }
        if (StringUtils.isNotBlank(MDC.get(AppConstants.REQUEST_PATH))) {
            MDC.remove(AppConstants.REQUEST_PATH);
        }
        if (StringUtils.isNotBlank(MDC.get(AppConstants.APP_VERSION))) {
            MDC.remove(AppConstants.APP_VERSION);
        }
        if (StringUtils.isNotBlank(MDC.get(AppConstants.AUTHORIZATION_HEADER))) {
            MDC.remove(AppConstants.AUTHORIZATION_HEADER);
        }
        if (StringUtils.isNotBlank(MDC.get(AppConstants.IP_ADDRESS))) {
            MDC.remove(AppConstants.IP_ADDRESS);
        }
        if (StringUtils.isNotBlank(MDC.get(AppConstants.USER_ID))) {
            MDC.remove(AppConstants.USER_ID);
        }
    }
}
